/* Copyright (C) 2011 The University of Michigan This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. Please send inquiries to powertutor@umich.edu */ package vn.cybersoft.obs.andriod.batterystats2.util; import android.os.SystemClock; public class Counter { public static final int WINDOW_MINUTE = 0; public static final int WINDOW_HOUR = 1; public static final int WINDOW_DAY = 2; public static final int WINDOW_TOTAL = 3; public static final CharSequence[] WINDOW_NAMES = { "Last minute", "Last Hour", "Last Day", "Total" }; // To be used for constructions like "Showing X over ..." public static final CharSequence[] WINDOW_DESCS = { "the last minute", "the last hour", "the last day", "all time" }; private static final long WINDOW_DURATIONS[] = { 60 * 1000, 60 * 60 * 1000, 24 * 60 * 60 * 1000 }; private long startTime; private long total; private SingleCounter[] counters; public Counter() { total = 0; startTime = SystemClock.elapsedRealtime(); counters = new SingleCounter[WINDOW_DURATIONS.length]; for (int i = 0; i < counters.length; i++) { counters[i] = new SingleCounter(); } } public void add(long x) { total += x; long now = SystemClock.elapsedRealtime() - startTime; for (int i = 0; i < counters.length; i++) { counters[i].add(x, now * SingleCounter.BUCKETS / WINDOW_DURATIONS[i]); } } public long get(int window) { if (window == WINDOW_TOTAL) { return total; } long now = SystemClock.elapsedRealtime() - startTime; return counters[window].get(now * SingleCounter.BUCKETS / WINDOW_DURATIONS[window], (1.0 * now * SingleCounter.BUCKETS % WINDOW_DURATIONS[window]) / WINDOW_DURATIONS[window]); } private static class SingleCounter { public static final int BUCKETS = 60; private long base; private int baseIdx; private long droppingBucket; private long[] bucketSum; private long total; public SingleCounter() { bucketSum = new long[BUCKETS]; } private void wind(long now) { if (base + 2 * BUCKETS <= now) { /* Completly clear the data structure. */ droppingBucket = 0; for (int i = 0; i < BUCKETS; i++) { bucketSum[i] = 0; } total = 0; base = now; baseIdx = 0; } else while (base + BUCKETS <= now) { droppingBucket = bucketSum[baseIdx]; total -= droppingBucket; bucketSum[baseIdx] = 0; base++; baseIdx = baseIdx + 1 == BUCKETS ? 0 : baseIdx + 1; } } public void add(long x, long now) { wind(now); total += x; int idx = (int) (baseIdx + now - base); bucketSum[idx < BUCKETS ? idx : idx - BUCKETS] += x; } /* * now gives the time slice that we want information for. prog, between * 0 and 1, gives the progress through the current time slice with 0 * indicating that it just started and 1 indicating that it is about to * end. */ public long get(long now, double prog) { wind(now); return total + (long) ((1.0 - prog) * droppingBucket); } } }